package cn.buk.qms.service;

import cn.buk.api.airskyhk.dto.*;
import cn.buk.api.szkj.dto.eterm.request.PnrRtRequest;
import cn.buk.api.szkj.dto.eterm.response.RtpnrResponse;
import cn.buk.api.szkj.service.SzkjEtermService;
import cn.buk.api.szkj.service.SzkjEtermServiceImpl;
import cn.buk.api.wechat.dto.WxTemplateDataParam;
import cn.buk.api.wechat.dto.WxTemplateSend;
import cn.buk.common.JsonResult;
import cn.buk.common.dto.eterm.PnrDto;
import cn.buk.qms.SmsUtil;
import cn.buk.tms.dao.FlightOrderDao;
import cn.buk.tms.dao.PnrDao;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.entity.bill.BillFlightTicket;
import cn.buk.tms.entity.config.EnterpriseConfig;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.tms.entity.order.flight.FlightOrder;
import cn.buk.tms.entity.order.flight.FlightOrderPassenger;
import cn.buk.tms.flight.dao.KeyCustomerPolicyDao;
import cn.buk.tms.flight.dto.CouponInfoDto;
import cn.buk.tms.flight.dto.FareInfoDto;
import cn.buk.tms.flight.dto.FlightOfferPrice;
import cn.buk.tms.flight.dto.SegmentInfoDto;
import cn.buk.tms.util.IdUtil;
import cn.buk.common.util.CheckUtil;
import cn.buk.common.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import jakarta.validation.constraints.NotNull;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static cn.buk.common.Constant.DATE_YYYY_MM_DD;
import static cn.buk.common.Constant.SUCCESS;
import static cn.buk.common.JsonResult.STATUS_OK;
import static cn.buk.tms.common.constant.TmsConstant.ID_TYPE_NI;
import static cn.buk.tms.common.constant.TmsOrderConstant.AUTO_PRINT_TICKET_NONE;
import static cn.buk.tms.entity.config.EnterpriseConfig.TMS_DEFAULT_LINK_MOBILE;

/**
 * @author yfdai
 */
public class BaseFlightOrderService extends BaseOrderService {

  private static final Logger logger = LogManager.getLogger(BaseFlightOrderService.class);

  /**
   * 南航的两字代码
   */
  protected final String AIRLINE_CZ_CODE = "CZ";

  private static final String SMS_TEMPLATE_1 = "%s乘机人：%s，行程：%s，已预定成功，每人：%s元。";

  /**
   * 出票完成短信模板
   */
  private static final String SMS_TEMPLATE_2 = "%s%s您好,您的行程%s已出票，票号：%s。请提前%d分钟到%s机场办理值机手续。";
  private static final String SMS_TEMPLATE_2_A = "%s%s您好,您的行程%s已出票，票号：%s。请提前%d分钟到%s机场办理值机手续。请关注微信公众号：%s。";

  private static final String SMS_TEMPLATE_3 = "%s%s 行程:,%s，价格:%d元,特价机票,不得改期,不得退票。行程确认无误,如需出票,请回复:出票,谢谢!";

  private static final String SMS_TEMPLATE_4 = "%s%s 行程:,%s。确认无误,请回复:出票,谢谢!";

  private static final String SMS_TEMPLATE_5 = "%s%s 行程:,%s，价格:%d元,行程确认无误,如需出票,请回复:出票,谢谢!";

  private static final String SMS_TEMPLATE_6 = "%s%s 行程:,%s，价格:%d元,同等舱位改期 :%d元,退票:%d元,确认出票,请回复:出票,谢谢!";

  /**
   * 用于标识机票订单是否停止CZ NDC自动开票
   */
  protected static final String CZ_NDC_ORDER_KEY = "%d_CZ_NDC_ORDER_STOP_%s";
  /**
   * 用于标识改签单
   */
  protected static final String CZ_NDC_CHANGE_ORDER_KEY = "%d_CZ_NDC_FLIGHT_CHANGE_ORDER_%s";
  /**
   * 用于标识CZ NDC支付时是否提示过支付失败
   */
  protected static final String CZ_NDC_AMOUNT_BALANCE = "%d_CZ_NDC_AMOUNT_BALANCE";

  /**
   * 用于保存某个shoppingResponse对应的价格
   */
  protected static final String CZ_NDC_SHOPPING_RESPONSE = "%d_CZ_NDC_SHOPPING_RESPONSE_%s";

  /**
   * EOTMS登录后给的会话token
   */
  protected static final String EOTMS_TOKEN = "EOTMS_TOKEN_%d_%d";

  /**
   * TMS用到的企业微信应用的网址
   */
  @Value("${url_tms_workwx_service}")
  protected String tmsWorkWxUrl;

  @Autowired
  protected FlightOrderDao flightOrderDao;

  @Autowired
  protected PnrDao pnrDao;

  @Autowired
  private KeyCustomerPolicyDao keyCustomerPolicyDao;


  protected JsonResult doSendFlightOrderSms(final int enterpriseId, final String username, final int orderId, final int psgId,
                                            final String mobileNo0, final String smsContent0, final int smsFormat) {
    if (StringUtils.trimToEmpty(mobileNo0).length() > 0 && !CheckUtil.isMobileNo(mobileNo0)) {
      return JsonResult.createJsonResult(-1, "手机号(" + mobileNo0 + ")格式不符");
    }

    FlightOrder flightOrder = flightOrderDao.getOrderDetailById(orderId);

    FlightOrderPassenger psgInfo = null;
    for (FlightOrderPassenger psg : flightOrder.getPassengers()) {
      if (psgId == psg.getId()) {
        psgInfo = psg;
        break;
      }
    }
    if (psgInfo == null) {
      return JsonResult.createJsonResult(-2, "无指定乘机人");
    }

    final String mobileNo = StringUtils.trimToEmpty(mobileNo0).length() == 0 ? psgInfo.getMobile() : mobileNo0.trim();
    if (!CheckUtil.isMobileNo(mobileNo)) {
      return JsonResult.createJsonResult(-3, "无符合要求的手机号");
    }

    final String smsContent = StringUtils.isBlank(smsContent0) ?
            generateFlightOrderSmsContentByPsgId(enterpriseId, flightOrder, psgId, smsFormat) : smsContent0;

    var smsDetail = SmsDetail.createSmsDetail(enterpriseId, username, mobileNo, smsContent, flightOrder.getOrderNo());

    try {
      sendWeixinTemplateMessage(enterpriseId, flightOrder);
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return sendSms(smsDetail);
  }

  private void sendWeixinTemplateMessage(final int enterpriseId, FlightOrder flightOrder) {
    //发送给订单的创建人
    var user = userDao.getUserByUsername(flightOrder.getOperator());
    if (user != null && user.getParentEnterprise() == enterpriseId) {
      var list = userDao.getUserBindWeixin(enterpriseId, user.getEnterpriseId(), user.getId());
      for(var ubw : list) {
        doSendWeixinTemplateMessage(ubw.getWeixinOpenId(), enterpriseId, flightOrder);
      }
    }
  }

  private void doSendWeixinTemplateMessage(final String openid, final int enterpriseId, final FlightOrder flightOrder) {
    WxTemplateSend wxTplRq = new WxTemplateSend();
    wxTplRq.setTouser(openid);
    wxTplRq.setTemplate_id("Ia0GPhta4IpUTcIqjIXdcjFQhrsUDItXdfAyxmrxIMo");

    String firstData = "您的机票已成功出票，祝您旅途愉快。";
    wxTplRq.getData().setFirst(WxTemplateDataParam.createByValue(firstData));

    wxTplRq.getData().setKeyword1(WxTemplateDataParam.createByValue(flightOrder.getOrderNo()));
    var sb = new StringBuilder();
    for (FlightOrderPassenger psg : flightOrder.getPassengers()) {
      sb.append(psg.getName()).append(", ");
    }
    wxTplRq.getData().setKeyword2(WxTemplateDataParam.createByValue(sb.toString()));

    processOrderAirportName(flightOrder);
    final String smsRouteInfo = SmsUtil.convertFlightOrder(flightOrder);
    wxTplRq.getData().setKeyword3(WxTemplateDataParam.createByValue(smsRouteInfo));

    final String dportName = flightOrder.getFlights().get(0).getFlight().getDepartureAirportName();

    wxTplRq.getData().setRemark(WxTemplateDataParam.createByValue(String.format("请提前%d分钟到%s机场办理值机手续。", 90, dportName)));

    final String url = generateTmsWxsTplUrl(enterpriseId, openid, flightOrder.getId(), OrderNoInfo.ORDER_FLIGHT);
    try {
      weixinService.buildUrlInWeixin(enterpriseId, url);
      wxTplRq.setUrl(weixinService.buildUrlInWeixin(enterpriseId, url));
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      wxTplRq.setUrl(url);
    }

    doSendWeixinTemplateMessage(enterpriseId, wxTplRq);

  }

  /**
   * 发送机票订单完成短信
   */
  protected void autoSendFlightOrderSms(final int enterpriseId, final String username, FlightOrder orderInfo) {
    final int orderId = orderInfo.getId();

    try {
      //DEBUG 发送给开发人员
      doSendWeixinTemplateMessage("oEK0T0sye8VHx3ywNellAehPY-8Y", enterpriseId, orderInfo);
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    //自动发送短信，需要判断企业客户的设置sms_mode
    if (orderInfo.getCustomer() == null) {
      //该客户不需要自动发送短信
      flightOrderDao.appendFlightOrderLog(enterpriseId, username, orderId, "散客目前设定不自动发送短信");
      return;
    } else if (orderInfo.getCustomer() != null && orderInfo.getCustomer().getSmsMode() == 0) {
      //该客户不需要自动发送短信
      flightOrderDao.appendFlightOrderLog(enterpriseId, username, orderId, "系统设定不需要自动发送短信");
      return;
    } else {
      flightOrderDao.appendFlightOrderLog(enterpriseId, username, orderId, "^_^将自动发送短信");
    }

    final int smsFormat = 0;

    for (FlightOrderPassenger psg : orderInfo.getPassengers()) {
      //发送给乘机人
      JsonResult jsonResult = this.doSendFlightOrderSms(enterpriseId, username, orderId, psg.getId(), null, null, smsFormat);
      if (!STATUS_OK.equalsIgnoreCase(jsonResult.getStatus())) {
        doSendAlert(enterpriseId, jsonResult.getErrmsg() + ": " + orderId + ", " + psg.getId() + ", " + username, "Dai", 0);
      }
      //发送给联系人
      if (orderInfo.getLinkPhone().length() == 11) {
        this.doSendFlightOrderSms(enterpriseId, username, orderId, psg.getId(), orderInfo.getLinkPhone(), null, smsFormat);
      }
    }
  }

  /**
   * 根据订单，生成指定乘机人的出票后通知短信内容
   */
  protected String generateFlightOrderSmsContentByPsgId(int enterpriseId, FlightOrder flightOrder, int psgId,
                                                        final int smsFormat) {

    FlightOrderPassenger psgInfo = null;
    for (FlightOrderPassenger psg : flightOrder.getPassengers()) {
      if (psgId == psg.getId()) {
        psgInfo = psg;
        break;
      }
    }
    if (psgInfo == null) {
      return null;
    }

    processOrderAirportName(flightOrder);

    return generateSmsContentByTemplate(enterpriseId, smsFormat, flightOrder, psgInfo);
  }

  private String generateSmsContentByTemplate(final int enterpriseId, final int smsFormat,
                                              FlightOrder flightOrder, FlightOrderPassenger psgInfo) {
    final String companySign = doGetEntCfg(enterpriseId, EnterpriseConfig.API_SMS_COMPANY_SIGN);
    final String weixinServiceNoName = doGetEntCfg(enterpriseId, EnterpriseConfig.ENT_WEIXIN_SERVER_NO_NAME);
    final String psgName = psgInfo.getName() + "(" + psgInfo.getIdNo() + ")";
    final String smsRouteInfo = SmsUtil.convertFlightOrder(flightOrder);
    final String smsTicketNo = psgInfo.getTicketNo().replace("-", "");
    final String dportName = flightOrder.getFlights().get(0).getFlight().getDepartureAirportName();
    final int price = (int) flightOrder.getAmount();
    //判断是否使用有 “请关注微信公众号：上海尚游国际旅行社有限公司。” 内容 yfdai 2021-11-01

    String smsContent = null;
    if (smsFormat == 0) {
      if (StringUtils.isBlank(weixinServiceNoName)) {
        smsContent = String.format(SMS_TEMPLATE_2, companySign, psgName, smsRouteInfo, smsTicketNo, 90, dportName);
      } else {
        smsContent = String.format(SMS_TEMPLATE_2_A, companySign, psgName, smsRouteInfo, smsTicketNo, 90, dportName, weixinServiceNoName);
      }
    } else if (smsFormat == 1) {
      smsContent = String.format(SMS_TEMPLATE_3, companySign, psgName, smsRouteInfo, price);
    } else if (smsFormat == 2) {
      smsContent = String.format(SMS_TEMPLATE_4, companySign, psgName, smsRouteInfo);
    } else if (smsFormat == 3) {
      smsContent = String.format(SMS_TEMPLATE_5, companySign, psgName, smsRouteInfo, price);
    } else if (smsFormat == 4) {
      smsContent = String.format(SMS_TEMPLATE_6, companySign, psgName, smsRouteInfo, price, 0, 0);
    }

    return smsContent;
  }


  protected String generateFlightOrderApprovalSmsContent(int enterpriseId, int orderId) {
    FlightOrder flightOrder = flightOrderDao.getOrderDetailById(orderId);
    processOrderAirportName(flightOrder);

    final String companySign = doGetEntCfg(enterpriseId, EnterpriseConfig.API_SMS_COMPANY_SIGN);

    final String psgInfo = SmsUtil.convertFlightOrderPsgInfo(flightOrder);
    final String smsRouteInfo = SmsUtil.convertFlightOrder(flightOrder);

    return String
            .format(SMS_TEMPLATE_1, companySign, psgInfo, smsRouteInfo, flightOrder.getAmount());
  }

  protected void doSendFlightOrderAlertByTaskCardMsg(final int enterpriseId, final int orderId, final String title, final String content,
                                                     final String toParty) {
    final String url = orderId > 0 ? tmsWorkWxUrl + "/h5/flt/order/" + orderId : null;
    doSendAlertByTaskCardMsg(enterpriseId, title, content, url, toParty);
  }

  /**
   * 发送机票订单取消开票申请
   */
  protected void doSendFlightOrderCancelRequestAlert(final int enterpriseId, final int orderId, final int cancelRequestId,
                                                     final String title, final String content,
                                                     final String toParty) {
    final String url = orderId > 0 ? tmsWorkWxUrl + "/h5/flt/order/" + orderId : null;
    doSendConfirmAlert(enterpriseId, title, content, url, toParty, TmsOrderConstant.FLIGHT_ORDER_CANCEL_REQUEST, cancelRequestId);
  }

  protected void doRefreshFlightOrderPnrDetail(final int enterpriseId, final String username, final int orderId,
                                               final String orderNo, final String pnrNo) {
    RtpnrResponse response = execApiRtPnr(enterpriseId, username, pnrNo, orderNo);
    if (response.getCode() == 1 && pnrNo.equalsIgnoreCase(response.getPnrInfo().getPnr())) {
      // 调用成功
      final String pnrDetail = response.getPnrInfo().getPnrDetail();
      flightOrderDao.updatePnrDetail(enterpriseId, username, orderId, pnrDetail);
      updatePnrDetail(enterpriseId, pnrDetail);
    } else {
      flightOrderDao.updateFlightOrderRefreshPnrStatusFailed(enterpriseId, username, orderId, "更新编码失败：" + response.getMsg());
    }
  }

  /**
   * 运行接口：提取编码
   * @param keyCustomerCode 大客户代码
   */
  protected RtpnrResponse execApiRt(final int enterpriseId, final String username, final String pnrNo,
                                    final String keyCustomerCode, final String orderNo, final String remark) {
    PnrRtRequest rtRequest = new PnrRtRequest();
    rtRequest.setPnrNo(pnrNo);
    rtRequest.setHk("0");
    rtRequest.setGetTicket("1");
    rtRequest.setGetRawdata(1);
    rtRequest.setGetPrice(1);
    if (keyCustomerCode != null) {
      rtRequest.setCustomerCode(keyCustomerCode);
    }

    return execRt(rtRequest, enterpriseId, username, orderNo, remark);
  }

  /**
   * 仅提取PNR内容
   */
  protected RtpnrResponse execApiRtPnr(final int enterpriseId, final String username, final String pnrNo,
                                       final String orderNo) {
    PnrRtRequest rtRequest = new PnrRtRequest();
    rtRequest.setPnrNo(pnrNo);
    //是否为预订编码,0否，1是
    rtRequest.setHk("0");
    //不用获取票号信息
    rtRequest.setGetTicket("0");
    //是否获取RT的原始信息，0否，1是
    rtRequest.setGetRawdata(1);
    //不需要价格
    rtRequest.setGetPrice(0);

    return execRt(rtRequest, enterpriseId, username, orderNo, "获取编码详情");
  }

  private RtpnrResponse execRt(PnrRtRequest rtRequest, final int enterpriseId, final String username,
                               final String orderNo, final String remark) {
    final int queryId = userDao.createEtermCmdLog(enterpriseId, username, remark, orderNo);

    final String etermUsername = getEtermUsername(enterpriseId);
    final String etermPassword = getEtermPassword(enterpriseId);

    SzkjEtermService szkjEtermService = createSzkjEtermService(enterpriseId);

    RtpnrResponse response = szkjEtermService.rtpnr(etermUsername, etermPassword, queryId, rtRequest);
    userDao.updateEtermCmdLog(queryId, response.getRequestStr(), response.getResponseStr());

    return response;
  }

  /**
   * 获取ETERM用户名
   * @param enterpriseId 企业id
   */
  protected String getEtermUsername(final int enterpriseId) {
    return doGetEntCfg(enterpriseId, EnterpriseConfig.ENTERPRISE_SZKJ_ETERM_USERNAME);
  }

  protected String getEtermPassword(final int enterpriseId) {
    return doGetEntCfg(enterpriseId, EnterpriseConfig.ENTERPRISE_SZKJ_ETERM_PASSWORD);
  }

  protected String getUsername(final int enterpriseId) {
    return doGetEntCfg(enterpriseId, EnterpriseConfig.ENTERPRISE_SZKJ_USERNAME);
  }

  protected SzkjEtermService createSzkjEtermService(final int enterpriseId) {
    SzkjEtermServiceImpl impl = new SzkjEtermServiceImpl(getUsername(enterpriseId), "http://www.kjyou.net/app/api/interface.php");
    impl.setDebugMode(false);
    return impl;
  }



  protected int updatePnrDetail(int enterpriseId, @NotNull final String pnrDetail) {
    //保存PNR内容到Pnr实体
    PnrDto pnrDto = new PnrDto();
    pnrDto.setPnrDetail(pnrDetail);
    Pnr pnr = new Pnr();
    BeanUtils.copyProperties(pnrDto, pnr, "pnrCommitResult");

    pnr.setEnterpriseId(enterpriseId);
    pnr.setPnrDetail(pnrDetail);
    pnr.setLinkphone(pnrDto.getLinkphone());

    return pnrDao.createOrUpdate(enterpriseId, pnr);
  }


  /**
   * 执行将乘机人票号回填到订单中
   * @param smsMode      1-自动发送短信
   */
  protected JsonResult execUpdateTicketNo(final int enterpriseId, final String username, final FlightOrder orderInfo, final int smsMode) {
    int retCode = flightOrderDao
            .updateTicketNo(enterpriseId, username, orderInfo.getId(), orderInfo.getPassengers());

    if (retCode > 0 && smsMode == 1) {
      //修改成功，自动发送短信
      autoSendFlightOrderSms(enterpriseId, username, orderInfo);
    }

    return JsonResult.createJsonResult(retCode);
  }


  protected void doFinishFlightOrder(final int enterpriseId, final String username, final int id) {
    // 检查票号在账单表中是否已经存在
    FlightOrder o = flightOrderDao.getOrderDetailById(id);
    for (FlightOrderPassenger psg : o.getPassengers()) {
      BillFlightTicket ticket = billService.searchFlightTicket(enterpriseId, psg.getTicketNo());
      if (ticket != null) {
        String content = "机票订单(" + o.getOrderNo() + ")的票号" + psg.getTicketNo() + "已存在于账单.";
        doSendAlert(enterpriseId, content, null, EntDepartment.DEPT_ADMINISTRATOR);
        return;
      }
    }

    if (flightOrderDao.finishFlightOrder(enterpriseId, username, id, null) > 0) {
      try {
        importService.importFlightOrder(enterpriseId, username, id);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }


  /**
   * 校验机票订单的乘机人是否符合年龄限制，目前针对大客户号订单
   *
   * @return true - 符合
   * false - 不符合
   */
  protected boolean isValidForAgeLimited(final int enterpriseId, final String username, final FlightOrder flightOrder,
                                         final int minAge, final int maxAge) {
    if (StringUtils.isBlank(flightOrder.getKeyCustomerNo())) {
      //没有大客户号，则任何年龄都是符合的
      return true;
    }

    flightOrderDao.appendFlightOrderLog(enterpriseId, username, flightOrder.getId(), "(私有政策)校验乘机人年龄");

    boolean blnContinue = true;
    StringBuilder remark = new StringBuilder("机票订单(" + flightOrder.getOrderNo() + ": ");

    for (FlightOrderPassenger psg : flightOrder.getPassengers()) {
      //有时需要从身份证号中提取生日 2021-7-2
      Date bd = psg.getBirthday();
      if (bd == null && psg.getIdType() == ID_TYPE_NI && psg.getIdNo() != null) {
        bd = IdUtil.retrieveBirthday(psg.getIdNo().trim());
      }

      if (bd != null) {
        final int age = DateUtil.calcAge(bd);
        if (age < minAge || age > maxAge) {
          blnContinue = false;
          remark.append(psg.getName()).append(" ").append(age).append("岁");
          break;
        }
      }
    }

    if (!blnContinue) {
      remark.append(")不符合大客户开票的年龄限制.").append("(").append(username).append(")");
      doSendAlert(enterpriseId, remark.toString(), null, EntDepartment.DEPT_TICKETING);
      flightOrderDao.updateFlightOrderAutoTicketing(enterpriseId, username, flightOrder.getId(),
              AUTO_PRINT_TICKET_NONE, remark.toString());
    }

    return blnContinue;
  }

  protected JsonResult doUpdateFlightOrderSupplierType(final int enterpriseId, final String username, final int orderId, final int supplierType) {
    List<Supplier> suppliers = enterpriseDao.searchSupplierByTicketingType(enterpriseId, supplierType);
    if (suppliers.size() == 1) {
      Supplier supplier = suppliers.get(0);

      PaymentMethod pm = enterpriseDao.getPaymentMethodById(enterpriseId, supplier.getPaymentMethodId());

      int retCode = flightOrderDao.updateSupplier(enterpriseId, username, orderId, supplier, pm);
      return JsonResult.createJsonResult(retCode);
    } else {
      return JsonResult.createJsonResult(-1, "未找到匹配供应商");
    }
  }

  /**
   * 查询大客户代码
   * @param enterpriseId 企业id
   * @param keyCustomerNo 传入的大客户代码
   * @return 返回大客户代码，如果无匹配，则返回传入的大客户代码
   */
  protected String queryRawKeyCustomerNo(final int enterpriseId, final String keyCustomerNo) {
    var policies = keyCustomerPolicyDao.searchFlightKeyCustomerPolicyByKeyCustomerNo(enterpriseId, keyCustomerNo);
    if (policies.isEmpty()) {
      return keyCustomerNo;
    }

    for(var p: policies) {
      if (StringUtils.isNotBlank(p.getRawKeyCustomerCode())) {
        return p.getRawKeyCustomerCode();
      }
    }

    return keyCustomerNo;
  }

  /**
   * 查找南航的价格
   * @param enterpriseId
   * @param username
   * @param flightOrder
   * @return
   */
  protected FlightOfferPrice offerCzNdcPrice(final int enterpriseId, final String username, final FlightOrder flightOrder) {
    var rq = new OfferPriceRequest();
    rq.getMemberInfo().setAccountNumber(doGetEntCfg(flightOrder.getEnterpriseId(), TMS_DEFAULT_LINK_MOBILE));

    //如果有PNR，则用PNR查询价格
    if (StringUtils.isNotBlank(flightOrder.getPnrNo())) {
      //获取大编码
      var bigPnr = prepareBigPnr4NdcPriceOffer(enterpriseId, username, flightOrder);
      if (StringUtils.trimToEmpty(bigPnr).length() < 6) {
        var result = new FlightOfferPrice();
        result.setErrcode(1000);
        result.setErrmsg("未找到大编码");
        //试试更新编码内容
        doRefreshFlightOrderPnrDetail(enterpriseId, username, flightOrder.getId(), flightOrder.getOrderNo(), flightOrder.getPnrNo());
        return result;
      }
      rq.getRequest().setPnr(bigPnr);
    } else {
      prepareRequest4NdcPriceOffer(flightOrder, rq);
    }

    //大客户代码
    if (StringUtils.isNotEmpty(flightOrder.getKeyCustomerNo())) {
      final String rawKeyCustomerNo = queryRawKeyCustomerNo(enterpriseId, flightOrder.getKeyCustomerNo());
      rq.getRequest().setBigClientId(rawKeyCustomerNo);
      rq.getPayloadAttributes().setSystem("B2G");
    }

    //记录查询日志
    final int queryId = userDao.createEtermCmdLog(enterpriseId, username, "CZ_NDC_订单价格确认", flightOrder.getOrderNo());
    rq.getPayloadAttributes().setTransactionId(queryId + "");

    var ndcService = createNdcService(enterpriseId);
    if (ndcService == null) {
      var result = new FlightOfferPrice();
      result.setErrcode(1000);
      result.setErrmsg("请联系管理员，配置CZ_NDC相关参数");
      return result;
    }

    OfferPriceResponse rs;
    try {
      rs = ndcService.searchOfferPrice(rq);
      userDao.updateEtermCmdLog(queryId, rs.getRequestStr(), rs.getResponseStr());
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      var result = new FlightOfferPrice();
      result.setErrcode(1001);
      result.setErrmsg("未找到任何内容 " + ex.getMessage());
      return result;
    }

    if (rs.getResponse() != null && rs.getResponse().getCouponInfoList() != null && !rs.getResponse().getCouponInfoList().isEmpty()) {
      doSendAlert(enterpriseId, flightOrder.getOrderNo() + "有优惠券可用, 请核对实际开票结果", "Dai", 0);
    }

    return convertFlightOfferPrice(rs);
  }


  /**
   * 为ndc 价格校验准备大编码
   */
  private String prepareBigPnr4NdcPriceOffer(int enterpriseId, String username, FlightOrder flightOrder) {
    if (StringUtils.isNotBlank(flightOrder.getBigPnrNo())) {
      return flightOrder.getBigPnrNo();
    } else {
      PnrDto pnrDto = new PnrDto();
      pnrDto.setPnrDetail(flightOrder.getPnrDetail());
      if (!flightOrder.getPnrNo().equalsIgnoreCase(pnrDto.getPnrNo())) {
        return null;
      }

      flightOrderDao.updateFlightOrderProperty(enterpriseId, username, flightOrder.getId(), "bigPnrNo", pnrDto.getBigPnrNo());
      return pnrDto.getBigPnrNo();
    }
  }


  private FlightOfferPrice convertFlightOfferPrice(OfferPriceResponse rs) {
    return convertFlightOfferPrice2(rs.getStatus(), rs.getResponse());
  }

  private FlightOfferPrice convertFlightOfferPrice2(ResponseStatus status, BaseShoppingResponse response) {
    var result = new FlightOfferPrice();

    if (!SUCCESS.equalsIgnoreCase(status.getStatus())) {
      result.setErrcode(1000);
      result.setErrmsg(status.getErrorCode() + ": " + status.getErrorMessage());
      return result;
    }

    result.setShoppingResponseId(response.getShoppingResponseId());

    for (var seg : response.getSegmentList()) {
      var dto = new SegmentInfoDto();

      dto.setSegmentKey(seg.getSegmentKey());
      dto.setDport(seg.getDeparture().getAirportCode());
      dto.setAport(seg.getArrival().getAirportCode());
      dto.setFlightNo(seg.getMarketingCarrierCode() + seg.getMarketingFlightNo());
      try {
        dto.setDdate(DateUtil.convertToDate(seg.getDeparture().getScheduledDate(), DATE_YYYY_MM_DD));
      } catch (ParseException e) {
        e.printStackTrace();
      }
      dto.setDtime(seg.getDeparture().getScheduledTime());
      dto.setAtime(seg.getArrival().getScheduledTime());

      result.getSegments().add(dto);
    }


    for (var dto : result.getSegments()) {
      //价格
      List<FareInfoDto> fareInfos = new ArrayList<>();
      processSegmentFareDetailList(response, dto, fareInfos);
      fareInfos = fareInfos.stream().sorted(Comparator.comparing(FareInfoDto::getBaseAmount)).collect(Collectors.toList());
      dto.getFareInfoDtos().addAll(fareInfos);

      //优惠券
      List<CouponInfoDto> couponInfos = new ArrayList<>();
      processSegmentCouponList(response, dto, couponInfos);
      dto.getCouponInfos().addAll(couponInfos);
    }

    return result;
  }



  private void processSegmentFareDetailList(BaseShoppingResponse response, SegmentInfoDto dto, List<FareInfoDto> fareInfos) {
    for (var fare : response.getFareDetailList()) {
      processSegmentFareDetail(fare, dto, fareInfos);
    }
  }

  private void processSegmentFareDetail(FareDetail fare, SegmentInfoDto dto, List<FareInfoDto> fareInfos) {
    var sr = fare.getSegmentRefs().get(0);
    if (fare.getSegmentRefs().size() > 1) {
      logger.warn("SegmentRefs size > 1 : {}", sr.getSegmentKey());
    }

    if (sr.getSegmentKey().equalsIgnoreCase(dto.getSegmentKey())) {
      dto.setSubclass(sr.getCabinCode());
    } else {
      return;
    }

    var fc = fare.getFareComponents().get(0);
    if (fare.getFareComponents().size() > 1) {
      logger.warn("FareComponents size > 1 : {}", sr.getSegmentKey());
    }
    for (var fpt : fc.getFarePriceTypes()) {
      var fit = new FareInfoDto();

      fit.setOfferItemId(fpt.getOfferItemId());
      fit.setPsgType(fpt.getPassengerType());
      fit.setBaseAmount(fpt.getBaseAmount());
      fit.setTotalTax(fpt.getTotalTaxes());
      fit.setTotalAmount(fpt.getTotalAmount());
      fit.setTotalFee(fpt.getTotalFee());
      fit.setFareBasisCode(fpt.getFareBasisCode());

      if (fpt.getFareRule() != null) {
        String temp = null;
        for (var info : fpt.getFareRule().getCategories()) {
          temp = temp == null ? info.getText().toString() : temp + "; " + info.getText().toString();
        }
        fit.setFareRule(temp);
      }

      fareInfos.add(fit);
    }
  }


  private void prepareRequest4NdcPriceOffer(FlightOrder flightOrder, OfferPriceRequest rq) {
    rq.getRequest().setDirectOnly(true);

    for (var flt : flightOrder.getFlights()) {
      cn.buk.api.airskyhk.dto.FlightInfo flightInfo = new cn.buk.api.airskyhk.dto.FlightInfo();
      rq.getRequest().getFlights().add(flightInfo);

      flightInfo.getDeparture().setAirportCode(flt.getFlight().getDport());
      flightInfo.getDeparture().setScheduledDate(flt.getFlight().getDdate());
      String dtime = flt.getFlight().getDtime().trim();
      if (dtime.length() == 4) {
        dtime = dtime.substring(0, 2) + ":" + dtime.substring(2, 4);
      }
      flightInfo.getDeparture().setScheduledTime(dtime);
      flightInfo.getDeparture().setTerminalName(flt.getFlight().getDterm());

      flightInfo.getArrival().setAirportCode(flt.getFlight().getAport());
      if (flt.getFlight().getArrivalDate() != null) {
        flightInfo.getArrival().setScheduledDate(flt.getFlight().getArrivalDate());
      } else {
        flightInfo.getArrival().setScheduledDate(flt.getFlight().getDdate());
      }
      String atime = flt.getFlight().getDtime().trim();
      if (atime.length() == 4) {
        atime = atime.substring(0, 2) + ":" + atime.substring(2, 4);
      }
      flightInfo.getArrival().setScheduledTime(atime);
      flightInfo.getArrival().setTerminalName(flt.getFlight().getAterm());

      flightInfo.setCabin(flt.getFlight().getSubclass());
      flightInfo.setLegId("0");

      flightInfo.setMarketingFlightNo(flt.getFlight().getFlightNo());
      flightInfo.setOperatingFlightNo(flt.getFlight().getFlightNo());
    }

    flightOrder.calcPsgCount();
    if (flightOrder.getAdultCount() > 0) {
      PaxQuery paxQuery = new PaxQuery();
      paxQuery.setPassengerNumber(flightOrder.getAdultCount());
      paxQuery.setPassengerType("ADT");
      rq.getRequest().getTravelers().add(paxQuery);
    }

    if (flightOrder.getChildCount() > 0) {
      PaxQuery paxQuery = new PaxQuery();
      paxQuery.setPassengerNumber(flightOrder.getChildCount());
      paxQuery.setPassengerType("CHD");
      rq.getRequest().getTravelers().add(paxQuery);
    }
  }


  private void processSegmentCouponList(BaseShoppingResponse response, SegmentInfoDto dto, List<CouponInfoDto> couponInfos) {
    for (var coupon : response.getCouponInfoList()) {
      processSegmentCouponDetail(coupon, dto, couponInfos);
    }
  }

  private void processSegmentCouponDetail(CouponInfo coupon, SegmentInfoDto dto, List<CouponInfoDto> couponInfos) {
    if (!coupon.getSegmentKey().equalsIgnoreCase(dto.getSegmentKey())) {
      return;
    }

    for (var detail : coupon.getCouponDetails()) {
      var couponInfoDto = new CouponInfoDto();
      couponInfoDto.setCouponNo(detail.getGroupId());
      couponInfoDto.setFaceValue(detail.getFaceValue());

      couponInfos.add(couponInfoDto);
    }
  }


  protected boolean isCzOrder(FlightOrder o) {
    for(var flt: o.getFlights()) {
      if (!AIRLINE_CZ_CODE.equalsIgnoreCase(flt.getFlight().getFlightNo().substring(0, 2))) {
        return false;
      }
    }
    return true;
  }
}
